//
//  SFAudioPlayer.m
//  Test
//
//  Created by xueshan1 on 2018/11/13.
//  Copyright © 2018年 xueshan1. All rights reserved.
//

#import "SFAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import "SFPlayerResourceLoader.h"
#import "NSURL+stream.h"
#import "SFFileHandle.h"

//asset key
NSString *const SF_Playable_Key = @"playable";
//playerItem key
NSString *const SF_Status_Key = @"status";
NSString *const SF_LoadedTimeRanges_Key = @"loadedTimeRanges";
NSString *const SF_PlaybackBufferEmpty_Key = @"playbackBufferEmpty";
NSString *const SF_PlaybackLikelyToKeepUp_Key = @"playbackLikelyToKeepUp";


@interface SFAudioPlayer ()<SFPlayerResourceLoadDelegate>

@property(nonatomic,strong)NSURL *audioURL;
@property(nonatomic,strong)AVPlayer *player;
@property(nonatomic,strong)AVPlayerItem *playerItem;
@property(nonatomic,strong)SFPlayerResourceLoader *resourceLoader;
//进度观察者
@property(nonatomic,strong)id progressObserver;
//是否有其他声音播放
@property(nonatomic,assign)BOOL isOtherPlaying;
//在后台
@property(nonatomic,assign)BOOL isBackground;

@end

@implementation SFAudioPlayer

+ (instancetype)shareInstance{
    static SFAudioPlayer *audioPlayer = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        audioPlayer = [[SFAudioPlayer alloc]init];
    });
    return audioPlayer;
}
- (void)dealloc{
    [[NSNotificationCenter defaultCenter]removeObserver:self];
}

//初始化
- (void)initPlayer{
    
    //默认值
    self.isBackground = NO;
    self.playState = SFAudioPlayerState_Stopped;
    [[AVAudioSession sharedInstance]setActive:YES error:nil];
    self.isOtherPlaying = [AVAudioSession sharedInstance].isOtherAudioPlaying;
    self.sessionCategory = SFAudioPlayerSessionCategory_Playback;
    self.needCustomeCache = NO;
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_audioPlayerInterrupted:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    
}
//播放一个音频
- (void)sf_playAudioWithURLString:(NSString *)audioURLString{
    if (!audioURLString.length) {
        return;
    }
    [self sf_playAudioWithURL:[NSURL URLWithString:audioURLString]];
}

- (void)sf_playAudioWithURL:(NSURL *)audioURL{
    if (![audioURL isKindOfClass:[NSURL class]]) {
        return;
    }
    self.audioURL = audioURL;
    [self sf_removeItemObserver];
 
    if (self.needCustomeCache) {
        self.resourceLoader = [SFPlayerResourceLoader new];
        self.resourceLoader.delegate = self;
        audioURL = [audioURL streamSchemeURL];
        NSString *cacheFile = [SFFileHandle existCacheFileWithUrl:audioURL];
        if (cacheFile) {
            self.playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:cacheFile]];
        }else{
            self.playerItem = [self loadItemWithURL:audioURL];
        }
    
    }else{
        self.playerItem = [self loadItemWithURL:audioURL];
    }
   
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
    
}
- (AVPlayerItem *)loadItemWithURL:(NSURL *)audioURL{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:audioURL options:nil];
    if (self.needCustomeCache) [asset.resourceLoader setDelegate:self.resourceLoader queue:dispatch_get_main_queue()];
    [asset loadValuesAsynchronouslyForKeys:@[SF_Playable_Key] completionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!asset.isPlayable) {
                NSLog(@"不能播放");
                self.playState = SFAudioPlayerState_Failed;
                [asset cancelLoading];
            }
            
        });
    }];
    
    return [AVPlayerItem playerItemWithAsset:asset];
}

- (AVPlayer *)player{
    if (!_player) {
        _player = [[AVPlayer alloc]init];
    }
    return _player;
}

//播放
- (void)sf_audioPlay{
    
    self.playState = SFAudioPlayerState_Playing;
    [self.player play];
}
//暂停
- (void)sf_audioPause{
    
    self.playState = SFAudioPlayerState_Pause;
    [self.player pause];
}
//释放播放器
- (void)sf_deallocPlayer{
    [self sf_audioPause];
    //解除激活,并还原其他应用播放器声音
    if (self.isOtherPlaying) {
        [[AVAudioSession sharedInstance]setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    }else{
        [[AVAudioSession sharedInstance]setActive:NO error:nil];
    }
 
    [self sf_removeItemObserver];
    
    if (self.player) {
        self.player = nil;
    }
    
    [self.player.currentItem cancelPendingSeeks];
    [self.player.currentItem.asset cancelLoading];
    
    [self.resourceLoader stopLoadding];
    
}

//重新播放
- (void)recyclePlay{
    if (!self.player) {
        return;
    }
    [self.player seekToTime:CMTimeMake(0, 1)];
    [self sf_audioPlay];
    
}
#pragma mark - notification
//播放结束
- (void)sf_playerDidPlayToEndTime:(NSNotification *)notification{
    NSLog(@"播放结束");
    self.playState = SFAudioPlayerState_Stopped;
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerDidPlayToEndTime:)]) {
        [self.delegate sf_playerDidPlayToEndTime:self];
    }
    
    if (self.isRecyclePlay) {
        [self recyclePlay];
    }
    
}
//被打断(其他音频/来电话)
- (void)sf_audioPlayerInterrupted:(NSNotification *)notification{
    NSDictionary *dic = notification.userInfo;
    if ([dic[AVAudioSessionInterruptionTypeKey] integerValue] == 1) {
        //被打断
        [self sf_audioPause];
    }else{
        //打断结束
        if ([dic[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == 1) {
            [self sf_audioPlay];
        }
    }
    
}
- (void)sf_appWillResignActive{
    self.isBackground = YES;
    [self sf_audioPause];
}
- (void)sf_appDidBecomeActive{
    if (self.player && self.isBackground) {
        [self sf_audioPlay];
    }
    
    self.isBackground = NO;
}

- (void)sf_removeItemObserver{
    if (self.player.currentItem) {
        [self.player.currentItem removeObserver:self forKeyPath:SF_Status_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_LoadedTimeRanges_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_PlaybackBufferEmpty_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF_PlaybackLikelyToKeepUp_Key];
    }
    
    if (self.player) {
        [[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        [self.player removeTimeObserver:self.progressObserver];
    }
    
}
- (void)sf_addItemObserver{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_playerDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_Status_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_LoadedTimeRanges_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_PlaybackBufferEmpty_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF_PlaybackLikelyToKeepUp_Key options:NSKeyValueObservingOptionNew context:nil];
    
    
    kWeakSelf;
    self.progressObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        
        weakSelf.sf_currentTime = (CGFloat)CMTimeGetSeconds(time);
        if (weakSelf.sf_totalTime) {
            weakSelf.sf_progress = weakSelf.sf_currentTime/weakSelf.sf_totalTime;
        }
        
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(sf_player:progress:currentTime:totalTime:)]) {
            [weakSelf.delegate sf_player:weakSelf progress:weakSelf.sf_progress currentTime:weakSelf.sf_currentTime totalTime:weakSelf.sf_totalTime];
        }
        if (weakSelf.progressChangeBlock) {
            weakSelf.progressChangeBlock(weakSelf.sf_progress);
        }
        
        NSLog(@"当前时间:%f,进度:%f",weakSelf.sf_currentTime,weakSelf.sf_progress);
        
    }];
    
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (object == self.player.currentItem) {
        if ([keyPath isEqualToString:SF_Status_Key]) {
            switch (_playerItem.status) {
                case AVPlayerItemStatusUnknown:
                    self.playState = SFAudioPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusUnknown:未知错误");
                    break;
                case AVPlayerItemStatusReadyToPlay:
                    //准备播放
                    [self sf_audioPlay];
                    
                    break;
                case AVPlayerItemStatusFailed:
                    self.playState = SFAudioPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusFailed:准备失败");
//                    if (self.player && [SFFileHandle existCacheFileWithUrl:self.audioURL]) {
//                        [self sf_audioPlay];
//                    }
                    break;
                    
                default:
                    break;
            }
            
        }else if ([keyPath isEqualToString:SF_LoadedTimeRanges_Key]){//缓存时间
            self.sf_totalTime = CMTimeGetSeconds(self.player.currentItem.duration);
//            NSLog(@"总时长:%f",self.sf_totalTime);
            [self addBufferProgressObserver];
        }else if ([keyPath isEqualToString:SF_PlaybackBufferEmpty_Key]){//缓冲是空的
            if (self.playerItem.playbackBufferEmpty) {
                self.playState = SFAudioPlayerState_Buffering;
            }
            
        }else if ([keyPath isEqualToString:SF_PlaybackLikelyToKeepUp_Key]){//缓冲达到可播放
            NSLog(@"缓冲达到可播放");
        }
        
    }
}
- (void)addBufferProgressObserver{
    CMTimeRange timeRange = [self.playerItem.loadedTimeRanges.firstObject CMTimeRangeValue];
    CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
    CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
    if (self.sf_totalTime != 0) {
        self.sf_bufferProgress = (startSeconds + durationSeconds)/self.sf_totalTime;
    }
    NSLog(@"缓冲进度:%f",self.sf_bufferProgress);
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_player:bufferProgress:totalTime:)]) {
        [self.delegate sf_player:self bufferProgress:self.sf_bufferProgress totalTime:self.sf_totalTime];
    }
    
}

#pragma mark - set
- (void)setPlayerItem:(AVPlayerItem *)playerItem{
    _playerItem = playerItem;
   
}
- (void)setSessionCategory:(SFAudioPlayerSessionCategory)sessionCategory{
    _sessionCategory = sessionCategory;
    switch (sessionCategory) {
        case SFAudioPlayerSessionCategory_Ambient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryAmbient error:nil];
            break;
        case SFAudioPlayerSessionCategory_SoloAmbient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategorySoloAmbient error:nil];
            break;
        case SFAudioPlayerSessionCategory_Playback:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback error:nil];
            break;
            
        default:
            break;
    }
}
- (void)setPlayState:(SFAudioPlayerState)playState{
    _playState = playState;
}
- (void)setSf_rate:(CGFloat)sf_rate{
    _sf_rate = sf_rate;
    self.player.rate = sf_rate;
}
- (void)setProgressValus:(CGFloat)progressValus{
    if (progressValus<0.0 || progressValus >1.0) {
        return;
    }
    _progressValus = progressValus;
    
    self.resourceLoader.isSeek = YES;

    [self sf_audioPause];
    [self.player seekToTime:CMTimeMake(floorf(self.sf_totalTime*progressValus), 1) toleranceBefore:CMTimeMake(1, 1) toleranceAfter:CMTimeMake(1, 1) completionHandler:^(BOOL finished) {
        if (finished) {
            NSLog(@"seekComplete!!");
            [self sf_audioPlay];
        }
    }];
    
}

#pragma mark - ResourceLoaderDelegate
- (void)resourceLoader:(SFPlayerResourceLoader *)loader cacheProgress:(CGFloat)cacheProgress{
    
//    NSLog(@"下载进度:%f",cacheProgress);
    
}





@end
